/**
 * 在这里定义与用户相关的路由处理函数，供/router/user.js模块使用
 */

// 导入db模块
const db = require('../db/index')
// 导入bcryptjs处理密码的模块
const bcrypt = require('bcryptjs')
// 用这个包来生成Token字符串
const jwt = require('jsonwebtoken')
// 导入全局的配置文件
const config = require('../config')
// 引用用来发送验证码的nodemailer
const nodemailer = require('nodemailer')
const randomstring = require('randomstring')

const util = require('util')
const query = util.promisify(db.query).bind(db)
// 辅助函数：验证验证码（新的！！！用这个！！！）
const verifyCode = async (email, inputCode) => {
  try {
    // 定义查找该用户验证码的sql语句
    const sqlStr = 'select * from user where email=? and expires_at > NOW()'
    // 执行sql语句
    const results = await query(sqlStr, [email])
    // console.log('result111:', results)
    if (results.length === 0) {
      return false
    }
    // 拿到用户数据库中存储的验证码
    const storeCode = results[0].code
    // console.log('storeCode:', storeCode, 'inputCode:', inputCode)
    // 比较验证
    if (storeCode === inputCode) {
      // 验证成功后删除验证码
      const sqlStr_delete_code = 'UPDATE user SET code = null WHERE email=?'
      db.query(sqlStr_delete_code, [email])
      return true
    }
    return false
  } catch (error) {
    console.error('验证验证码失败:', error)
    throw error
  }
}

// 辅助函数：验证验证码(旧的！！！！用不了！！！！)
// const verifyCode = (email, inputCode) => {
//   try {
//     // 定义查找该用户验证码的sql语句
//     const sqlStr = 'select * from user where email=? and expires_at > NOW()'
//     // 执行sql语句
//     // 存储回调函数的返回值
//     let flag = false
//     db.query(sqlStr, [email], (err, results) => {
//       if (err) {
//         return
//       }
//       console.log('result111:', results)
//       // 判断返回结果
//       if (results.length === 0) {
//         return
//       }
//       // 拿到用户数据库中存储的验证码
//       const storeCode = results[0].code
//       console.log('storeCode:', storeCode, 'inputCode:', inputCode)
//       // 比较验证
//       if (storeCode === inputCode) {
//         // 验证成功后删除验证码
//         const sqlStr_delete_code = 'UPDATE user SET code = null WHERE email=?'
//         db.query(sqlStr_delete_code, [email])
//         return flag = true
//       }
//     })
//     if (flag) {
//       console.log('flag:', flag)
//       return true
//     }
//     console.log('flag:', flag)
//     return false
//   } catch (error) {
//     console.error('验证验证码失败:', error)
//     throw error
//   }
// }



// 注册用户的处理函数
exports.register = (req, res) => {
  // 1. 检测表单数据是否合法
  // 获取客户端提交到服务器上的用户信息
  const userInfo = req.body
  // 对表单中的数据进行合法性检验
  if (!userInfo.studentId) {
    return res.send({ status: 1, message: '学号不能为空' })
  } else if (!userInfo.password) {
    return res.send({ status: 1, message: '密码不能为空' })
  } else if (!userInfo.email) {
    return res.send({ status: 1, message: '邮箱不能为空' })
  } else if (!userInfo.repassword) {
    return res.send({ status: 1, message: '确认密码不能为空' })
  }
  // 2. 检测学号是否被占用
  // 定义SQL语句，查询学号是否被占用
  const sqlStr = 'select * from user where studentId=?'
  // 执行SQL语句
  db.query(sqlStr, [userInfo.studentId], (err, results) => {
    if (err) {
      return res.send({ status: 1, message: err.message })
    }
    // 未出错，判断学号是否被占用
    if (results.length > 0) {
      return res.send({ status: 1, message: '学号被占用，请更换其他学号' })
    }

    // 学号未被占用，继续后续流程

    // 3. 对密码进行加密
    // 使用bcrypt包，优点：① 无法逆向破解  ② 同一明文密码加密，得到的加密结果各不相同
    // 先调用bcrypt.hashSync(明文密码, 随机盐的长度) 方法对密码进行加密
    userInfo.password = bcrypt.hashSync(userInfo.password, 10)
    // 4. 插入新用户
    // 定义插入新用户的sql语句
    const sqlZhuCe = 'insert into user set ?'
    // 调用db.query()执行sql语句
    db.query(sqlZhuCe,
      { studentId: userInfo.studentId, email: userInfo.email, password: userInfo.password },
      (err, results) => {
        // 判断是否成功
        if (err) {
          return res.send({ status: 1, message: err.message })
        }
        // 判断影响行数是否为1 => 防止同一时间同一个学号被多个人注册
        if (results.affectedRows !== 1) {
          return res.send({ status: 1, message: '注册用户失败，请稍后重试' })
        }
        // 注册用户成功
        res.send({ status: 0, message: '注册成功' })
      }
    )
  })
}

// 用户登录的处理函数
exports.login = (req, res) => {
  // 接收表单数据
  const userInfo = req.body
  console.log(userInfo)
  // 先判断登陆方式
  if (userInfo.loginType === 'studentId_password') {
    // 定义学号密码登陆方式的sql语句
    const sqlStr_name = 'select * from user where studentId=?'
    // 执行sql语句，根据学号查询用户信息
    db.query(sqlStr_name, [userInfo.studentId], (err, results) => {
      // 判断是否查询成功
      if (err) {
        return res.send({ status: 1, message: err })
      }
      // 执行sql语句成功，但是获取的条数不等于1
      if (results.length === 0) {
        return res.send({ status: 1, message: '该用户不存在' })
      } else if (results.length !== 1) {
        return res.send({ status: 1, message: '登陆失败' })
      }
      // TODO：判断密码是否正确
      const cmpresult = bcrypt.compareSync(userInfo.password, results[0].password)
      if (!cmpresult) {
        return res.send({ status: 1, message: '密码错误' })
      }
      // TODO：在服务器端生成Token字符串
      // 生成token时要剔除密码和头像,剔除后,user中只保留id,studentId,email四个值
      const user = { ...results[0], password: '', user_pic: '' }
      // 安装jsonwebtoken包
      // 对用户信息进行加密,生成token字符串
      const tokenStr = jwt.sign(user, config.jwtSecretKey, { expiresIn: config.expiresIn })
      res.send({ status: 0, message: '登录成功', token: `Bearer ${tokenStr}` })
    })
  } else if (userInfo.loginType === 'email_password') {
    // 定义邮箱密码登陆方式的sql语句
    const sqlStr_email = 'select * from user where email=?'
    // 执行sql语句，根据邮箱查询用户信息
    db.query(sqlStr_email, [userInfo.email], async (err, results) => {
      // 判断是否查询成功
      if (err) {
        return res.send({ status: 1, message: err })
      }
      // 执行sql语句成功，但是获取的条数不等于1
      if (results.length === 0) {
        return res.send({ status: 1, message: '该用户不存在' })
      } else if (results.length !== 1) {
        return res.send({ status: 1, message: '登录失败' })
      }
      // TODO：判断验证码是否正确
      const isTrue = await verifyCode(userInfo.email, userInfo.code)
      // 验证码错误
      console.log('isTrue:', isTrue)
      if (!isTrue) {
        return res.send({ status: 1, message: '验证码错误或已过期' })
      }
      // TODO：在服务器端生成Token字符串
      // 生成token时要剔除密码和头像,剔除后,user中只保留id,studentId,email四个值
      const user = { ...results[0], password: '', user_pic: '' }
      // 安装jsonwebtoken包
      // 对用户信息进行加密,生成token字符串
      const tokenStr = jwt.sign(user, config.jwtSecretKey, { expiresIn: config.expiresIn })
      res.send({ status: 0, message: '登录成功', token: `Bearer ${tokenStr}` })
    })
  }
}

// 获取注册id（userId）
exports.getUserId = (req, res) => {
  const userInfo = req.body
  console.log('获取注册序号req:' + req)
  console.log('获取注册序号查询参数:' + userInfo)
  const sqlStr = 'select id from user where studentId=?'
  db.query(sqlStr, [userInfo.studentId], (err, result) => {
    // 查询出错
    if (err) {
      return res.send({ status: 1, message: err.message })
    }
    console.log(result)
    // 未出错，判断是否查询到数据
    if (result.length === 0) {
      return res.send({ status: 1, message: '没有该用户的注册id' })
    } else {
      return res.send({ status: 0, message: '查询注册id成功', userId: result[0].id })
    }
  })
}


// 创建可重用的 transporter 对象用于发送邮件
const transporter = nodemailer.createTransport({
  // service: 'gmail', // 使用 Gmail 发送邮件，也可以配置 SMTP 设置
  host: 'smtp.126.com', // SMTP服务器地址
  port: 465, // 端口号
  secure: true, // 使用SSL
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASS
  }
})

// 辅助函数：生成并存储验证码
const generateAndStoreVerificationCode = async (email) => {
  // 生成验证码
  const code = randomstring.generate({
    length: 6,  //验证码长度
    charset: 'numeric'  //可以选择 'alphabetic', 'numeric', 'hexadecimal', 'binary' 或者自定义字符集
  })
  // 存储验证码
  // const createdAt = new Date()
  const expiresAt = new Date(Date.now() + 5 * 60 * 1000) // 验证码有效期为 5 分钟
  try {
    const sqlStr = 'UPDATE user SET code=?, expires_at=? WHERE email=?'
    // 'INSERT INTO user (email, code, expires_at) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE code=?, expires_at=? '
    await db.query(sqlStr, [code, expiresAt, email])
    return { code, expiresAt }
  } catch (error) {
    console.error('存储验证码失败:', error)
    throw error
  }
}

// 邮箱登录时发送验证码的处理函数
exports.sendVerificationCode = async (req, res) => {
  // 接收邮箱号
  const { email } = req.body
  if (!email) {
    return res.send({ status: 1, message: '请提供邮箱地址' })
  }
  try {
    const { code, expiresAt } = await generateAndStoreVerificationCode(email)
    // 构建邮件内容
    const mailOptions = {
      from: process.env.EMAIL_USER,
      to: email,
      subject: `您的验证码 ${code}`,
      text: `您好，您的验证码是：${code}。请不要告诉他人。验证码将在 ${expiresAt.toISOString()} 前有效。`,
      html: `<b>你的验证码是 ${code}，请勿告诉他人。</b>` // HTML 内容
    }
    // console.log('发送前' + process.env.EMAIL_USER + process.env.EMAIL_PASS)
    await transporter.sendMail(mailOptions)
    res.send({ status: 0, message: '验证码已发送，请查收邮件' })
  } catch (error) {
    res.send({ status: 1, message: '发送验证码时出错' })
  }
}


